using System;
using System.Collections.Generic;
using System.Configuration;
using System.Reflection;
using System.Threading;

namespace HF.Repository
{
    public sealed class RepositoryFactory
    {
        public static readonly string ConfigName = "RepositoryAssembly";

        //public static T Create<T>() where T : class //, IRepository<RepositoryModel>
        //{
        //    string iName = typeof(T).Name; //IModelName
        //    string tName = iName.Substring(1); //ModelName

        //    string ass = ConfigurationManager.AppSettings[ConfigName];
        //    string typeName = string.Format("{0}.{1}", ass, tName);
        //    object v = Assembly.Load(ass).CreateInstance(typeName);
        //    return v as T;
        //}


        private static readonly Dictionary<string, object> repositoryCache = new Dictionary<string, object>();
        private static readonly ReaderWriterLockSlim repositoryCacheLock = new ReaderWriterLockSlim();

        internal static object Create(Type type)
        {
            string tName = type.Name; //ModelName
            string ass = ConfigurationManager.AppSettings[ConfigName];
            string typeName = string.Format("{0}.{1}", ass, tName);

            object rep = CacheHelper.Get((out object p) => repositoryCache.TryGetValue(typeName, out p),
                                         () =>
                                         //Assembly.Load(ass).GetType(typeName).GetConstructor(new Type[0]).FastInvoke(),//
                                         Assembly.Load(ass).CreateInstance(typeName),
                                         p => repositoryCache[typeName] = p,
                                         repositoryCacheLock
                );
            return rep;
        }

        public static IRepository<T> Create<T>() where T : RepositoryModel
        {
            object rep = Create(typeof (T));
            return rep as IRepository<T>;
        }

        public static IReadonlyRepository<T> CreateReadonly<T>() where T : ReadonlyRepositoryModel
        {
            object rep = Create(typeof (T));
            return rep as IReadonlyRepository<T>;
        }
    }
}